#include <stdarg.h>
#include <glib.h>
#include <SDL.h>
#include "racanhack.h"
#include "task.h"

static struct _task task_list_0, task_list_1;
static struct _task *active_task_list, *expired_task_list;

static void task_append_to_expired(struct _task *task);

void task_init()
{
  active_task_list = &(task_list_0);
  expired_task_list = &(task_list_1);
  active_task_list->next = active_task_list->prev = active_task_list;
  expired_task_list->next = expired_task_list->prev = expired_task_list;
}

void task_free()
{
  struct _task *task, *next;
  for (task = active_task_list->next; task != active_task_list; task = next) {
    next = task->next;
    my_free(task);
  };
  for (task = expired_task_list->next; task != expired_task_list; task = next) {
    next = task->next;
    my_free(task);
  };
}

struct _task *task_add(state (*fp)(struct _task *task), ...)
{
  struct _task *task;
  va_list ap;
  int i;
  task = my_new(struct _task, 1);
  task->fp = fp;
  task->count = 0;
  task->alive = TRUE;
  va_start(ap, fp);
  for (i = 0; i < MAX_NUM_POINTER; i++) {
    task->pointer[i] = va_arg(ap, gpointer);
  };
  va_end(ap);
  task_append_to_expired(task);
  return task;
}

static void task_append_to_expired(struct _task *task) 
{
  task->next = expired_task_list;
  task->prev = expired_task_list->prev;
  task->prev->next = task;
  expired_task_list->prev = task;
}

void task_schedular()
{
  struct _task *task, *temp;
  for (task = active_task_list->next; task != active_task_list; task = active_task_list->next) {
    task->prev->next = task->next;
    task->next->prev = task->prev;
    if (task->alive) {
      (*task->fp)(task);
      task->count++;
      if (task->count >= G_MAXUINT) task->count = 1;
      task_append_to_expired(task);
      continue;
    } else {
      my_free(task);
      continue;
    };
  };
  g_assert(active_task_list->prev == active_task_list);
  g_assert(active_task_list->next == active_task_list);
  temp = active_task_list;
  active_task_list = expired_task_list;
  expired_task_list = temp;
}
